package model

import (
	"encoding/json"
	"errors"
	"fmt"
	"my-go-chat/message"

	"github.com/garyburd/redigo/redis"
)

//我们在服务器启动后就初始化一个userDao实例
//当作一个去哪句的比那辆，在需要和redis操作时 ，直接使用即可

var (
	MyUserDao *UserDao
)

type UserDao struct {
	pool *redis.Pool
}

//使用工厂模式 创建一个UserDao实例

func NewUserDao(pool *redis.Pool) (userDao *UserDao) {
	userDao = &UserDao{
		pool: pool,
	}
	return
}

//1.根据一个用户id返回用户实例  或者err
//这里的方法是只在userdao内使用的工具  不提供给外部使用
func (ud *UserDao) getUserById(conn redis.Conn, id int) (user *User, err error) {
	//通过给定的id 去查询这个用户
	res, err := redis.String(conn.Do("hget", "users", id))
	if err != nil {
		if err == redis.ErrNil { //没有找到对应的id
			err = ERROR_USER_NOTEXISTS
		}
		return
	}

	//这里我们要把res反序列化为User实例
	user = &User{} //这里注意对user 进行初始化  因为声明的没有分配空间
	err = json.Unmarshal([]byte(res), &user)
	if err != nil {
		fmt.Println("数据库数据反序列化出错 err=", err)
		return
	}
	return
}

//1完成登录的校验  Login
//2 如果id pwd 都正确  返回一个user 实例
//3 如果id 或者pwd 有错误 则返回对应的错误信息

func (ud *UserDao) Login(userId int, userPwd string) (user *User, err error) {
	//首先对userdao中的连接池中取得一个连接
	conn := ud.pool.Get()
	defer conn.Close()
	user, err = ud.getUserById(conn, userId)
	if err != nil {
		return
	}
	//这时得到了用户的相关信息
	if user.UserPwd != userPwd {
		err = ERROR_USER_PWDWRONG
		return
	}
	return
}

//数据库想过语句可以作为全局常量  怎加可扩展性
//这里利用率User作为参数  从而增加模块性  注意这里的逻辑
func (ud *UserDao) Register(user message.User) (err error) {
	conn := ud.pool.Get()
	defer conn.Close()
	_, err = ud.getUserById(conn, user.UserId)
	if errors.Is(err, ERROR_USER_NOTEXISTS) {
		//这里说明用户不存在 可以注册
		data, err := json.Marshal(user)
		if err != nil {
			return fmt.Errorf("注册发生错误 %w", err)
		}
		_, err = conn.Do("Hset", "users", user.UserId, string(data))
		if err != nil {
			return fmt.Errorf("注册失败 %w", err)
		}
		return nil
	} else if err == nil {
		return ERROR_USER_EXISTS
	} else {
		return fmt.Errorf("注册发生未知错误 %w", err)
	}

}
